package br.com.ps.bombertournament.game.object;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

import br.com.ps.bombertournament.game.AnimationListener;
import br.com.ps.bombertournament.game.BaseGameObject;
import br.com.ps.bombertournament.game.Renderer;
import br.com.ps.bombertournament.game.MappedGameObject;
import br.com.ps.bombertournament.game.animation.AnimationGameObject;
import br.com.ps.bombertournament.game.math.Rectangle;
import br.com.ps.bombertournament.game.scene.BattleScene;

public class Player extends MappedGameObject implements AnimationListener {

	private String configurations;
	private boolean dead;
	private boolean passWall;
	
	private Rectangle rect1 = new Rectangle();
	private Rectangle rect2 = new Rectangle();
	private int bombsPower = 1;
	private int maxBombs = 1;
	
	private List<Bomb> bombs = new ArrayList<Bomb>();
	
	private int speedyWalk = 3;
	
	public enum Keyboard {
		RIGHT,
		LEFT,
		UP,
		DOWN,
		SPACE
	}
	
	public enum Animations {
		WALK_RIGHT,
		WALK_LEFT,
		WALK_UP,
		WALK_DOWN,
		DIE
	}
	
	public Player() {}
	
	public Player(String configurations) {
		this.configurations = configurations;
	}
	
	@Override
	public String getMapPath() {
		return configurations != null ? configurations : super.getConfigurations().getString(MappedGameObject.CONFIGURATIONS_PROPERTY);
	}
	
	@Override
	public void onRemove() {
		// Do nothing
	}

	@Override
	public void onCollision(BaseGameObject other) {
		if (dead) {
			return;
		}
		
		if (other instanceof SuperWall || (other instanceof Wall && passWall == false)) {
			boolean recalculatePos = false;
			
			// With and Height of the Rectangle, will be used to know if the hit on the wall was by any extremity
			int rectSize = (int) Math.round(this.getVolume().getWidth() * 0.35);
			{
				/*
				 * Help the player to walk when the player hit on the wall in extremities
				 * DownLeft
				 *   
				 *          ____
				 *         |    |
				 *         |    |Player
				 *    ____ O____|     
				 *   |    O
				 *   |    |Wall
				 *   |____| 
				 */
				rect1.set(this.getVolume().x, this.getVolume().y, rectSize, rectSize);
				rect2.set(other.getX() + other.getWidth() - rectSize,
						other.getY() + other.getHeight() - rectSize,
						rectSize, rectSize);
				
				if (rect1.intercept(rect2)) {
					System.out.println("OnCollision: DownLeft");

					if (currentAnimation != null) {
						if (Animations.WALK_DOWN.name().equals(this.currentAnimation.getName())) {
							recalculatePos = true;
							this.setPosition(this.getX() + 1, this.getY());
						} else if (Animations.WALK_LEFT.name().equals(this.currentAnimation.getName())) {
							recalculatePos = true;
							this.setPosition(this.getX(), this.getY() + 1);
						}
					}
				}
			}
			
			{
				/*
				 * Help the player to walk when the player hit on the wall in extremities
				 * DownRight
				 *   
				 *    ____
				 *   |    |
				 *   |    |Player
				 *   |____O ____     
				 *         O    |
				 *         |    |Wall
				 *         |____| 
				 */
				rect1.set(this.getVolume().x + this.getVolume().width - rectSize,
						this.getVolume().y,
						rectSize, rectSize);
				rect2.set(other.getX(),
						other.getY() + other.getHeight() - rectSize,
						rectSize, rectSize);
				if (rect1.intercept(rect2)) {
					System.out.println("OnCollision: DownRight");
					
					if (currentAnimation != null) {
						if (Animations.WALK_DOWN.name().equals(this.currentAnimation.getName())) {
							recalculatePos = true;
							this.setPosition(this.getX() - 1, this.getY());
						} else if (Animations.WALK_RIGHT.name().equals(this.currentAnimation.getName())) {
							recalculatePos = true;
							this.setPosition(this.getX(), this.getY() + 1);
						}
					}
				}
			}
			
			{	
				/*
				 * Help the player to walk when the player hit on the wall in extremities
				 * UpLeft
				 *    ____
				 *   |    |
				 *   |    |Wall
				 *   |____O ____ 
				 *         O    |
				 *         |    |Player
				 *         |____|     
				 */
				rect1.set(this.getVolume().x,
						this.getVolume().y + this.getVolume().height - rectSize,
						rectSize, rectSize);
				rect2.set(other.getX() + other.getWidth() - rectSize,
						other.getY(),
						rectSize, rectSize);
				if (rect1.intercept(rect2)) {
					System.out.println("OnCollision: UpLeft");
					
					if (currentAnimation != null) {
						if (Animations.WALK_LEFT.name().equals(this.currentAnimation.getName())) {
							recalculatePos = true;
							this.setPosition(this.getX(), this.getY() - 1);
						} else if (Animations.WALK_UP.name().equals(this.currentAnimation.getName())) {
							recalculatePos = true;
							this.setPosition(this.getX() + 1, this.getY());
						}
					}
				}
			}
			
			{
				/*
				 * Help the player to walk when the player hit on the wall in extremities
				 * UpRight
				 *          ____
				 *         |    |
				 *         |    |Wall
				 *    ____ O____|
				 *   |    O
				 *   |    |Player
				 *   |____|     
				 */
				rect1.set(this.getVolume().x + this.getVolume().width - rectSize,
						this.getVolume().y + this.getVolume().height - rectSize,
						rectSize, rectSize);
				rect2.set(other.getX(), other.getY(), rectSize, rectSize);
				if (rect1.intercept(rect2)) {
					System.out.println("OnCollision: UpRight");
					
					if (currentAnimation != null) {
						if (Animations.WALK_RIGHT.name().equals(this.currentAnimation.getName())) {
							recalculatePos = true;
							this.setPosition(this.getX(), this.getY() - 1);
						} else if (Animations.WALK_UP.name().equals(this.currentAnimation.getName())) {
							recalculatePos = true;
							this.setPosition(this.getX() - 1, this.getY());
						}
					}
				}
			}
			
			/*if (recalculatePos == false) {
				// Recalculate the position of the player when hit on the wall
				if (super.currentAnimation != null) {
					if (Animations.WALK_UP.name().equals(super.currentAnimation.getName())) {
						super.setPosition(this.getX(), other.getY() - other.getHeight());
					} else if (Animations.WALK_DOWN.name().equals(super.currentAnimation.getName())) {
						super.setPosition(this.getX(), other.getY() + this.getVolume().getHeight());
					} else if (Animations.WALK_LEFT.name().equals(super.currentAnimation.getName())) {
						super.setPosition(other.getX() + this.getVolume().getWidth(), this.getY());
					} else if (Animations.WALK_RIGHT.name().equals(super.currentAnimation.getName())) {
						super.setPosition(other.getX() - this.getVolume().getWidth(), this.getY());
					}
				}
				super.stop();
			}*/
		} else if (other instanceof BombFire && dead == false) {
			dead = true;
			super.play(Animations.DIE.name());
		}
	}
	
	@Override
	public boolean play(String animation) {
		boolean result = this.animations.containsKey(animation);
		
		if (result) {
			AnimationGameObject tempAnimationGameObject = this.animations.get(animation);
			
			if (tempAnimationGameObject != currentAnimation) {
				this.currentAnimation = this.animations.get(animation);
				this.currentAnimation.reset();
			} else {
				if (this.currentAnimation.isFinished()) {
					this.currentAnimation.reset();
				}
			}
		}
		
		return result;
	}
	
	public boolean play(Animations animation) {
		return play(animation.name());
	}
	
	@Override
	public void animationUpdated() {
		if (Animations.WALK_UP.name().equals(currentAnimation.getName())) {
			super.setPosition(super.getX(), super.getY() + (speedyWalk * Renderer.scaleY));
		} else if (Animations.WALK_DOWN.name().equals(currentAnimation.getName())) {
			super.setPosition(super.getX(), super.getY() - (speedyWalk * Renderer.scaleY));
		} else if (Animations.WALK_RIGHT.name().equals(currentAnimation.getName())) {
			super.setPosition(super.getX() + (speedyWalk * Renderer.scaleX), super.getY());
		} else if (Animations.WALK_LEFT.name().equals(currentAnimation.getName())) {
			super.setPosition(super.getX() - (speedyWalk * Renderer.scaleX), super.getY());
		}
	}
	
	public boolean processEvent(Keyboard keyboard) {
		if(dead) {
			return false;
		}
		
		boolean result = false;
		
		switch(keyboard) {
			case UP:
				play(Animations.WALK_UP);
				
				result = true;
			break;
			
			case DOWN:
				play(Animations.WALK_DOWN);
				
				result = true;
			break;
			
			case RIGHT:
				play(Animations.WALK_RIGHT);
				
				result = true;
			break;
			
			case LEFT:
				play(Animations.WALK_LEFT);
				
				result = true;
			break;
			
			case SPACE:
				
				for (int i = 0; i < bombs.size(); i++) {
					if (bombs.get(i).isOnScene() == false) {
						bombs.remove(i--);
					}
				}
				
				if (bombs.size() < maxBombs) {
					Bomb bomb = FactoryGameObject.createBomb(bombsPower);
					
					calculateBombPosition(bomb);
					
					super.getLayer().add(bomb);
					bombs.add(bomb);
					
					result = true;
				}
			break;
		}
		
		return result;
	}

	private void calculateBombPosition(Bomb bomb) {
		int battleDimmensionX = 0;
		int battleDimmensionY = 0;
		int positionBattleX = 0;
		int positionBattleY = 0;
		
		float witdhFloor = bomb.getVolume().width;
		float heightFloor = bomb.getVolume().height;
		
		if (super.getLayer() != null 
				&& super.getLayer().getRenderer() != null 
				&& super.getLayer().getRenderer().getScene() != null
				&& super.getLayer().getRenderer().getScene() instanceof BattleScene) {
			BattleScene battleScene = (BattleScene) super.getLayer().getRenderer().getScene();
			
			battleDimmensionX = battleScene.getBattleDimmensionX();
			battleDimmensionY = battleScene.getBattleDimmensionY();
			
			positionBattleX = battleScene.getPositionBattleX();
			positionBattleY = battleScene.getPositionBattleY();
		}
		
		float resultPositionX = 0;
		float resultPositionY = 0;
		double distance = -1;
		for (int i = 1; i < battleDimmensionX; i++) {
			for (int j = 1; j < battleDimmensionY; j++) {
				
				{ // Removing the walls
					// Removing the wall with the same position of the SuperWalls 
					if (i % 2 == 0 && j % 2 == 0) {
						continue;
					}
				}
				
				float positionX = (positionBattleX + (witdhFloor * i)) * Renderer.scaleX;
				float positionY = (positionBattleY + (heightFloor * j)) * Renderer.scaleY;
				
				double currentDistance = Point2D.distance(super.getX(), super.getY(), positionX, positionY);
				if (distance == -1 || currentDistance < distance) {
					distance = currentDistance;
					resultPositionX = positionX;
					resultPositionY = positionY;
				}
			}
		}
		
		bomb.setPosition(resultPositionX, resultPositionY);
	}
}
